
package de.justphil.tcg.tcgandroidclient.gui.cardfinder;

import java.util.ArrayList;
import java.util.List;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;

import de.justphil.tcg.tcgandroidclient.Example;
import de.justphil.tcg.tcgandroidclient.R;
import de.justphil.tcg.tcgandroidclient.content.rest.RESTFoundMsgData;
import de.justphil.tcg.tcgandroidclient.content.rest.RESTGeoCard;
import de.justphil.tcg.tcgandroidclient.content.rest.RESTGeoRq;
import de.justphil.tcg.tcgandroidclient.network.rest.RESTMessengerService;
import de.justphil.tcg.tcgandroidclient.util.GeoCalculation;
import de.justphil.tcg.tcgandroidclient.util.StringTools;
import de.justphil.tcg.tcgandroidclient.util.TCGLog;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.widget.Toast;

public class CardFinderAct extends MapActivity implements OnCardFoundListener {
	
	private MapView mapView;
	private MyLocationOverlay myLocationOverlay;
	private Messenger restMessenger;
	private Messenger messenger;
	private boolean bound;
	private CardsOverlay cardsOverlay;
	private List<RESTGeoCard> cards = new ArrayList<RESTGeoCard>();
	private ProgressDialog dialog;
	/**
	 * Class for interacting with the main interface of the service.
	 */
	private ServiceConnection connection = new ServiceConnection() {
		
		public void onServiceConnected(ComponentName className, IBinder binder) {
		
			restMessenger = ((RESTMessengerService.RESTBinder) binder).getMessenger(messenger);
			bound = true;
			sendGeoRq();
		}
		
		public void onServiceDisconnected(ComponentName className) {
		
			restMessenger = null;
			bound = false;
		}
	};
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
	
		super.onCreate(savedInstanceState);
		setContentView(R.layout.card_finder);
		initializeComponents();
		messenger = new Messenger(new Handler() {
			
			@Override
			public void handleMessage(Message msg) {
			
				CardFinderAct.this.handleMessage(msg);
			}
		});
	}
	
	@Override
	protected void onStart() {
	
		super.onStart();
		// Bind to the service
		if (!bindService(new Intent(this, RESTMessengerService.class), connection,
				Context.BIND_AUTO_CREATE)) {
			throw new IllegalStateException("Thread binding failed!");
		}
		mapView.setEnabled(true);
		myLocationOverlay.enableMyLocation();
	}
	
	@Override
	protected void onStop() {
	
		super.onStop();
		// Unbind from the service
		if (bound) {
			unbindService(connection);
			bound = false;
		}
		mapView.setEnabled(false);
		myLocationOverlay.disableMyLocation();
	}
	
	@Override
	protected boolean isRouteDisplayed() {
	
		// TODO Auto-generated method stub
		return false;
	}
	
	private void sendGeoRq() {
	
		ProgressDialog d = getDialog();
		String text = "Requesting card update...";
		d.setMessage(text);
		d.show();

		RESTGeoRq restGeoRq =
				new RESTGeoRq(Example.GEO_CENTER_LAT, Example.GEO_CENTER_LONG, Example.GEO_RADIUS);
		Message msg = Message.obtain(null, RESTMessengerService.MSG_GEO_RQ, restGeoRq);
		try {
			restMessenger.send(msg);
		}
		catch (RemoteException e) {
			throw new RuntimeException("Could not send Message!");
		}
	}
	
	private void addCard(RESTGeoCard card, CardsOverlay overlay) {
	
		if (card == null) {
			throw new IllegalArgumentException("The card mus not be null!");
		}
		GeoPoint point = new TCGGeoPoint(card.getLatitude(), card.getLongitude());
		TCGLog.i(new Object[] {
			"Adding card: " + card });
		OverlayItem overlayitem =
				new OverlayItem(point, "Card Type: " + card.getCardType(), "Card Id: "
						+ card.getCardId());
		overlay.addOverlay(overlayitem);
	}
	
	private void handleMessage(Message msg) {
	
		switch (msg.what) {
			case RESTMessengerService.MSG_FOUND_RESPONSE:
				handleFoundResponseMsg();
				break;
			case RESTMessengerService.MSG_GEO_RESPONSE:
				handleGeoResponseMsg((List<RESTGeoCard>) msg.obj);
				break;
			case RESTMessengerService.MSG_ERROR:
				handleErrorMsg(msg.arg1, (String) msg.obj);
				break;
			case RESTMessengerService.MSG_NOT_RESPONDING:
				handleNotRespondingMsg();
				break;
			default:
				throw new IllegalArgumentException("Message type " + msg.what + " is unknown!");
		}
	}
	
	private void handleFoundResponseMsg() {
	
		Toast.makeText(this, "Validated by server!", Toast.LENGTH_LONG).show();
		sendGeoRq();
	}
	
	
	private void handleGeoResponseMsg(List<RESTGeoCard> cards) {

		ProgressDialog d = getDialog();
		if (d.isShowing()) {
			d.dismiss();
		}
		List<Overlay> mapOverlays = mapView.getOverlays();
		if (this.cardsOverlay != null) {
			mapOverlays.remove(this.cardsOverlay);
		}
		Drawable drawable = this.getResources().getDrawable(R.drawable.overlay26);
		CardsOverlay overlay = new CardsOverlay(drawable, this);
		this.cardsOverlay = overlay;
		mapOverlays.add(overlay);
		this.cards.clear();
		for (RESTGeoCard card : cards) {
			addCard(card, overlay);
			this.cards.add(card);
		}
	}
	
	private void handleNotRespondingMsg() {
	
		ProgressDialog d = getDialog();
		if (d.isShowing()) {
			d.dismiss();
		}
		Toast.makeText(this, "The REST server is not responding!", Toast.LENGTH_LONG).show();
	}
	
	private void handleErrorMsg(int code, String message) {
	
		ProgressDialog d = getDialog();
		if (d.isShowing()) {
			d.dismiss();
		}
		String text = StringTools.getString(new Object[] {
				"Error response ", code, ": ", message });
		Toast.makeText(this, text, Toast.LENGTH_LONG).show();
		TCGLog.w(new Object[] {
			text });
	}
	
	private void initializeComponents() {
	
		mapView = (MapView) findViewById(R.id.mapview1);
		myLocationOverlay = new TCGMyLocationOverlay(this, mapView, cards, this);
		mapView.getOverlays().add(myLocationOverlay);
	}
	
	@Override
	public void onCardFound(RESTGeoCard card, Location location) {
	
		cards.remove(card);
		String geoHash =
				GeoCalculation.getLocationHash(location.getLatitude(), location.getLongitude(),
						card.getCardId());
		RESTFoundMsgData data =
				new RESTFoundMsgData(location.getLatitude(), location.getLongitude(), card.getCardId(),
						geoHash);
		Message msg = Message.obtain(null, RESTMessengerService.MSG_FOUND_RQ, data);
		try {
			restMessenger.send(msg);
		}
		catch (RemoteException e) {
			throw new RuntimeException("Could not send Message!");
		}
		ProgressDialog d = getDialog();
		String text = StringTools.getString(new Object[] {
				"Found a Card: ", card.getCardId(), "\n", "Waiting for validation..." });
		d.setMessage(text);
		d.show();
	}
	
	private ProgressDialog getDialog() {
	
		if (dialog == null) {
			dialog = new ProgressDialog(this);
		}
		return dialog;
	}
}
